﻿using System;
using System.Diagnostics;
using System.Globalization;

namespace OverStore.Runtime.ObjectRepository.Depot.IdentifierGenerator
{
    /// <summary>
    /// Generates sequence of integer using specified starting result and increment. 
    /// </summary>
    /// <typeparam name="TInstance">The type of the instance.</typeparam>
    /// <typeparam name="TIdentifier">The type of the identifier. 
    /// The identifier type must be convertible from <see cref="System.Int32"/> that is used for actual identifier generating.</typeparam>
    public sealed class SequentialGenerator<TInstance, TIdentifier> : IIdentifierGenerator<TInstance, TIdentifier>
        where TInstance : class
    {
        private readonly int _Increment;
        private int _CurrentValue;

        /// <summary>
        /// Initializes a new instance of the <see cref="SequentialGenerator{TInstance, TIdentifier}"/> class.
        /// </summary>
        /// <param name="startingValue">The starting result.</param>
        /// <param name="increment">The increment using to calculate next identifier.</param>
        public SequentialGenerator(int startingValue, int increment)
        {
            if (increment == 0)
                throw new ArgumentOutOfRangeException("increment", "Increment can't be zero.");
            _CurrentValue = startingValue;
            _Increment = increment;
        }

        /// <summary>
        /// Obtain next identifier for specified instance.
        /// </summary>
        /// <param name="instance">The instance to obtain identifier for it.</param>
        /// <returns>
        /// The next result of identifier for specified instance.
        /// </returns>
        /// <exception cref="T:OverStore.Runtime.Repository.Depot.DepotException">The error occured due generating identifier.</exception>
        public TIdentifier NextIdentifier(TInstance instance)
        {
            Debug.Assert(instance != null, "Generates identifier for null instance.");
            _CurrentValue += _Increment;
            return (TIdentifier)Convert.ChangeType(_CurrentValue, typeof(TIdentifier), CultureInfo.InvariantCulture);
        }
    }
}
